#include <AT91SAM7S256.h>
#include "Comunicaciones.h"
#include "Colas.h"
#include "Globales.h"
#include "LCD.h"

/**
 * Divisor para obtener un baud rate de aproximadamente 38400 bps
 */
const int CD_US0 = 79;

/**
 * Divisor para obtener un baud rate de aproximadamente 9600 bps
 */
const int CD_US1 = 313;

//Terminador de mensajes


void setupUSART0(void);
void sendString(unsigned char* string, short n);
void sendChar(unsigned char charac);
void intToStr(unsigned char* str, short n, short num);

void setupUSART0(void) {
	//Activa el reloj para el USART0
	AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_US0);

	//Da el control de los pines RX y TX al USART0
	AT91C_BASE_PIOA->PIO_PDR = AT91C_PA6_TXD0 | AT91C_PA5_RXD0;
	AT91C_BASE_PIOA->PIO_ASR = AT91C_PA6_TXD0 | AT91C_PA5_RXD0;

	//Reinicia y deshabilita la transmision y recepcion en el USART0
	AT91C_BASE_US0->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS
			| AT91C_US_TXDIS;

	//Establece el modo de operacion del USART0 (Sin bit de paridad y 8 bits de datos)
	AT91C_BASE_US0->US_MR = AT91C_US_PAR_NONE | (3 << 6);

	//Establece el baud rate en el USART0
	AT91C_BASE_US0->US_BRGR = CD_US1;

	//Habilita la transmision y recepcion en el USART0
	AT91C_BASE_US0->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
}

int received_ACK(void) {

	int contador = 0;
	char flag = 0;
	char ACK1 = 0;

	while (!(AT91C_BASE_US0->US_CSR & AT91C_US_RXRDY)) {
		vTaskDelay(1000);
		contador = contador + 1;
		if (TIMEOUT == contador) {
			writeStatus(UNCONNECTED);
			return 0;
		}
	}
	ACK1 = AT91C_BASE_US0->US_RHR;
	if (ACK1 == ACK) {
		flag = 1;
	} else {
		writeStatus(UNCONNECTED);
	}
	return flag;
}

void sendString(unsigned char* string, short n) {
	short i;
	char temp;
	for (i = 0; i < n; i++) {
		temp = string[i];
		AT91C_BASE_US0->US_THR = temp;
		while (!((AT91C_BASE_US0->US_CSR) & AT91C_US_TXEMPTY)) {
		}
	}
}

void sendChar(unsigned char charac) {
	AT91C_BASE_US0->US_THR = charac;
	while (!((AT91C_BASE_US0->US_CSR) & AT91C_US_TXEMPTY)) {
	}
}

void setup_Comunicaciones(void) {
	setupUSART0();
}

void intToStr(unsigned char* str, short n, short number) {
	short i;
	short temp = number;
	char tmpChar;
	for (i = n - 1; i >= 0; i--) {
		tmpChar = (char) ((temp % 10) + 0x30);
		str[i] = tmpChar;
		temp = temp / 10;
	}
}

/**
 * Version 1 (Auto-Start con Hostlist)
 */
//void checkConex(void *pvParameters) {
//	char command;
//
//	while (!(AT91C_BASE_US0->US_CSR & AT91C_US_RXRDY)) {
//		vTaskDelay(1000);
//	}
//	command = AT91C_BASE_US0->US_RHR;
//	status = CONNECTED;
//}
/**
 * Version 2 (Manual connection mode en el XPort)
 */
void checkConex(void) {
	char command;
	while (1) {
		command = 0x43;
		sendChar(command);
		sendString("192.168.0.102/5791", 18);
		command = 0x0D;
		sendChar(command);
		while (!(AT91C_BASE_US0->US_CSR & AT91C_US_RXRDY)) {
			vTaskDelay(1000);
		}
		command = AT91C_BASE_US0->US_RHR;
		if (command == 0x43) {
			writeStatus(CONNECTED);
			return;
		}
	}
}

void setupLink(void) {

	unsigned char Encabezado[ENCABEZADO_LENGTH] = "H|\\^&|||";
	unsigned char zonaStr[2];
	unsigned char terminador[5] = "L|1|N";
	unsigned char Zona[ZONA_MSG_LENGTH] = "Z|||";
	unsigned char flag = 0;
	//Identificador del dispositivo
	unsigned char DISPOSITIVO_ID[9] = "Prototype";
	//Identificador del host PC
	unsigned char PC_HOST[7] = "PC_Test";
	//Version del firmware
	unsigned char VERSION[5] = "1.0.0";
	char zona = readZonaActual();
	intToStr(zonaStr, 2, zona);

	sendChar(ENQ);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	flag = 0;
	sendString(Encabezado, ENCABEZADO_LENGTH);
	sendString(DISPOSITIVO_ID, DISP_LENGTH);
	sendString("|||||", 5);
	sendString(PC_HOST, PC_HOST_LENGTH);
	sendString("||T|", 4);
	sendString(VERSION, VERSION_LENGTH);
	sendChar(CR);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	flag = 0;
	sendString(Zona, ZONA_MSG_LENGTH);
	sendString(zonaStr, 2);
	sendString("||||H", 5);
	sendChar(CR);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	flag = 0;
	sendString(terminador, TERMINADOR_LENGTH);
	sendChar(CR);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	flag = 0;
	sendChar(EOT);
	writeStatus(READY);
	return;
}

void sendData(void) {

	unsigned char Encabezado[ENCABEZADO_LENGTH] = "H|\\^&|||";
	unsigned char Data[DATA_LENGTH] = "D|";
	unsigned char DataDummy[DATA_DUMMY_LENGTH] =
			"D|0000||00:00:00||000.00^ppm|00.00^C||||||||00";
	//Identificador del dispositivo
	unsigned char DISPOSITIVO_ID[9] = "Prototype";
	//Identificador del host PC
	unsigned char PC_HOST[7] = "PC_Test";
	//Version del firmware
	unsigned char VERSION[5] = "1.0.0";
	unsigned char terminador[5] = "L|1|N";
	unsigned char seqStr[4];
	unsigned char time[2];
	unsigned char met1Str[3];
	unsigned char met2Str[2];
	unsigned char tempt1Str[2];
	unsigned char tempt2Str[2];
	unsigned char zonaStr[2];
	char flag;
	short hora;
	short min;
	short sec;
	short met1;
	short met2;
	short tempt1;
	short tempt2;
	short zonaDato;
	int seqMsg = readSecuencia();
	DatoComunicaciones dato;
	writeStatus(SENDING);
	//Enviar ENQ
	sendChar(ENQ);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	flag = 0;
	//Enviar HEADER
	sendString(Encabezado, ENCABEZADO_LENGTH);
	sendString(DISPOSITIVO_ID, 9);
	sendString("|||||", 5);
	sendString(PC_HOST, 7);
	sendString("||", 2);
	sendString("T|", 2);
	sendString(VERSION, 5);
	sendChar(CR);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	while (xQueueReceive(colaComunicaciones, &dato, portMAX_DELAY) == pdTRUE) {
		intToStr(seqStr, 4, seqMsg);
		hora = (short) dato.hora;
		min = (short) dato.minuto;
		sec = (short) dato.segundos;
		met1 = dato.datoMetano / 100;
		met2 = dato.datoMetano % 100;
		tempt1 = dato.datoTemperatura / 100;
		tempt2 = dato.datoTemperatura % 100;
		zonaDato = (short) dato.zona;

		//Enviar DATO
		sendString(Data, DATA_LENGTH);
		sendString(seqStr, 4);
		sendString("||", 2);
		intToStr(time, 2, hora);
		sendString(time, 2);
		sendChar(':');
		intToStr(time, 2, min);
		sendString(time, 2);
		sendChar(':');
		intToStr(time, 2, sec);
		sendString(time, 2);
		sendString("||", 2);
		intToStr(met1Str, 3, met1);
		sendString(met1Str, 3);
		sendChar('.');
		intToStr(met2Str, 2, met2);
		sendString(met2Str, 2);
		sendString("^ppm|", 5);
		intToStr(tempt1Str, 2, tempt1);
		sendString(tempt1Str, 2);
		sendChar('.');
		intToStr(tempt2Str, 2, tempt2);
		sendString(tempt2Str, 2);
		sendString("^C||||||||", 10);
		intToStr(zonaStr, 2, zonaDato);
		sendString(zonaStr, 2);
		sendChar(CR);

		flag = received_ACK();
		if (!flag) {
			return;
		}
		seqMsg++;
		writeSecuencia(seqMsg);
	}
	sendString(DataDummy, DATA_DUMMY_LENGTH);
	sendChar(CR);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	sendString(terminador, TERMINADOR_LENGTH);
	sendChar(CR);
	flag = received_ACK();
	if (!flag) {
		return;
	}
	sendChar(EOT);
	writeStatus(READY);
	return;
}

